<?php
/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */

require_once('includes/functions/module_functions.php');
class usps
{
	var $code, $enabled, $addr_info_enabled;
    	function usps() 
	{
		$this->module_key = 'MODULE_SHIPPING_USPS';
		$this->code = 'usps';
		$this->enabled = ((MODULE_SHIPPING_USPS_STATUS == 'true') ? true : false);
		$this->sort_order = MODULE_SHIPPING_USPS_SORT_ORDER;
		$this->addr_info_enabled = ((MODULE_SHIPPING_USPS_ADDR_INFO_STATUS == 'true') ? true : false);

		$this->domestic_services = array(
					//'EXPRESS',
					'FIRST CLASS',
					'PRIORITY',
					'PARCEL'
					);

		$this->international_services = array(
					//'Global Express Guaranteed',
					//'Global Express Guaranteed Non-Document Rectangular',
					//'Global Express Guaranteed Non-Document Non-Rectangular',
					//'USPS GXG Envelopes',
					//'Express Mail International (EMS)',
					//'Express Mail International (EMS) Flat Rate Envelope',
					'Priority Mail International',
					//'Priority Mail International Flat Rate Envelope',
					//'Priority Mail International Regular/Medium Flat-Rate Boxes',
					//'Priority Mail International Large Flat-Rate Box',
					//'Priority Mail International Small Flat-Rate Box',
					//'First Class Mail International Large Envelope',
					'First Class Mail International Package'
					);

	}

    	function cityStateLookup($params)
	{	
		$postcode = $params['postcode'];

        	$request  = '<CityStateLookupRequest USERID="' . MODULE_SHIPPING_USPS_USERID . '" PASSWORD="' . MODULE_SHIPPING_USPS_PASSWORD . '">';
		$request .= '<ZipCode ID="0">' .
			'<Zip5>' . $postcode . '</Zip5>' .
			'</ZipCode>';
		$request .= '</CityStateLookupRequest>';
		$request = 'API=CityStateLookup&XML=' . urlencode($request);


		$body = '';

		include_once('includes/classes/http_client.php');

		$http = new httpClient();
		if ($http->Connect('production.shippingapis.com', 80))
		{
			$http->addHeader('Host', 'production.shippingapis.com');
			$http->addHeader('User-Agent', 'osCommerce');
			$http->addHeader('Connection', 'Close');
			if ($http->Get('/shippingapi.dll?' . $request)) $body = $http->getBody();
			$http->Disconnect();
		}
		else 
		{
			$returnArray['error'] = 'Unable to make connection to production.shippingapis.com';
			return $returnArray;
		}

		if (preg_match('/<Error>/xsmi', $body)) {
			$number = preg_match('/<Number>(.*)<\/Number>/xsmi', $body, $regs);
			$number = $regs[1];
			$description = preg_match('/<Description>(.*)<\/Description>/xsmi', $body, $regs);
			$description = $regs[1];
			$returnArray['error'] = $number . ' - ' . $description;
			return $returnArray;
		}

		$city = preg_match('/<City>(.*)<\/City>/xsmi', $body, $regs);
		$city = $regs[1];
		$state = preg_match('/<State>(.*)<\/State>/xsmi', $body, $regs);
		$state = $regs[1];

		$returnArray['city'] = $city;
		$returnArray['state'] = $state;

		return $returnArray;	
	}


    	function quote($params, &$checkout_component)
	{
//var_dump($params);
		if (!$this->enabled) return false;

		$shipping_service = $params['shipping_service'];
		if ($shipping_service == null || strlen($shipping_service) == 0 || !(in_array($shipping_service, $this->domestic_services) || in_array($shipping_service, $this->international_services)))
			$shipping_service = null;

		$shipping_weight = (double)$params['shipping_weight'];
		//USPS will not return results with zero weight.
		if ($shipping_weight == 0) $shipping_weight = .1;
		$shipping_pounds = floor ($shipping_weight);
		$shipping_ounces = round(16 * ($shipping_weight - floor($shipping_weight)));
		
		$shipping_num_boxes = $params['shipping_num_boxes'];
	
		$machinable = 'False';
		$container = 'None';
		$size = 'REGULAR';
		
		//confirm Zone
		$check_flag = check_zone(MODULE_SHIPPING_USPS_ZONE, $checkout_component->shipTo['country_id'], $checkout_component->shipTo['zone_id']);
		if ($check_flag == false) return false;

		$quotes['code'] = $this->code;
		$quotes['tax_class'] = MODULE_SHIPPING_USPS_TAX_CLASS;

		//domestic
		if ($checkout_component->shipTo['country'] == $checkout_component->shipFrom['country'])
		{
        		$request  = '<RateRequest USERID="' . MODULE_SHIPPING_USPS_USERID . '" PASSWORD="' . MODULE_SHIPPING_USPS_PASSWORD . '">';
        		$services_count = 0;

        		if ($shipping_service != null)
			{
				//restrict
          			$this->domestic_services = array($shipping_service);
        		}

			reset($this->domestic_services);
			$services_count = 0;
			foreach ($this->domestic_services as $key)
			{
				$request .= '<Package ID="' . $services_count . '">' .
					'<Service>' . $key . '</Service>' .
					'<ZipOrigination>' . $checkout_component->shipFrom['postcode'] . '</ZipOrigination>' .
					'<ZipDestination>' . $checkout_component->shipTo['postcode'] . '</ZipDestination>' .
					'<Pounds>' . $shipping_pounds . '</Pounds>' .
					'<Ounces>' . $shipping_ounces . '</Ounces>' .
					'<Container>' . $container . '</Container>' .
					'<Size>' . $size . '</Size>' .
					'<Machinable>' . $machinable . '</Machinable>' .
					'</Package>';
				$services_count++;
			}
			$request .= '</RateRequest>';
			$request = 'API=Rate&XML=' . urlencode($request);
		} 
		//International
		else 
		{
			$request  = '<IntlRateRequest USERID="' . MODULE_SHIPPING_USPS_USERID . '" PASSWORD="' . MODULE_SHIPPING_USPS_PASSWORD . '">' .
				'<Package ID="0">' .
				'<Pounds>' . $shipping_pounds . '</Pounds>' .
				'<Ounces>' . $shipping_ounces . '</Ounces>' .
				'<MailType>Package</MailType>' .
				'<Country>' . $checkout_component->shipTo['country'] . '</Country>' .
				'</Package>' .
				'</IntlRateRequest>';

			$request = 'API=IntlRate&XML=' . urlencode($request);
		}
		$body = '';

		include_once('includes/classes/http_client.php');

		$http = new httpClient();
		if ($http->Connect('production.shippingapis.com', 80))
		{
			$http->addHeader('Host', 'production.shippingapis.com');
			$http->addHeader('User-Agent', 'osCommerce');
			$http->addHeader('Connection', 'Close');
			if ($http->Get('/shippingapi.dll?' . $request)) $body = $http->getBody();
			$http->Disconnect();
		}
		else 
		{
			$quotes['error'] = 'Unable to make connection to production.shippingapis.com';
			return $quotes;
		}

		$response = array();
		while (true) {
 			if ($start = strpos($body, '<Package ID=')) {
				$body = substr($body, $start);
				$end = strpos($body, '</Package>');
				$response[] = substr($body, 0, $end+10);
				$body = substr($body, $end+9);
			}
			else {
				break;
			}
		}

		//Calculate Shipping
		$rates = array();
		//domestic
		if ($checkout_component->shipTo['country'] == $checkout_component->shipFrom['country'])
		{
			if (sizeof($response) == '1') {
				if (preg_match('/<Error>/xsmi', $response[0])) {
					$number = preg_match('/<Number>(.*)<\/Number>/xsmi', $response[0], $regs);
					$number = $regs[1];
					$description = preg_match('/<Description>(.*)<\/Description>/xsmi', $response[0], $regs);
					$description = $regs[1];
					$quotes['error'] = $number . ' - ' . $description;
					return $quotes;
				}
			}

 			$n = sizeof($response);
			for ($i=0; $i<$n; $i++)
			{
				if (strpos($response[$i], '<Postage>')) {
					$service = preg_match('/<Service>(.*)<\/Service>/xsmi', $response[$i], $regs);
					$service = $regs[1];
					$postage = preg_match('/<Postage>(.*)<\/Postage>/xsmi', $response[$i], $regs);
					$postage = $regs[1];
					$rates[] = array('service' => $service, 'postage' => (double)$postage);
				}
			}
		} 
		//International
		else 
		{
			if (preg_match('/<Error>/xsmi', $response[0])) {
				$number = preg_match('/<Number>(.*)<\/Number>/xsmi', $response[0], $regs);
				$number = $regs[1];
				$description = preg_match('/<Description>(.*)<\/Description>/xsmi', $response[0], $regs);
				$description = $regs[1];
				$quotes['error'] = $number . ' - ' . $description;
				return $quotes;
        		}

          		$body = $response[0];
			$services = array();
			while (true) {
				if ($start = strpos($body, '<Service ID=')) {
					$body = substr($body, $start);
					$end = strpos($body, '</Service>');
					$services[] = substr($body, 0, $end+10);
					$body = substr($body, $end+9);
				} 
				else {
					break;
				}
			}

			$size = sizeof($services);
			for ($i=0, $n=$size; $i<$n; $i++)
			{
				if (strpos($services[$i], '<Postage>')) {
					$service = preg_match('/<SvcDescription>(.*)<\/SvcDescription>/xsmi', $services[$i], $regs);
					$service = $regs[1];
					$postage = preg_match('/<Postage>(.*)<\/Postage>/xsmi', $services[$i], $regs);
					$postage = $regs[1];

					if ($shipping_service != null && $service != $shipping_service) {
						continue;
					}
					else if (!(in_array($service, $this->international_services))) {
						continue;
					}

					$rates[] = array('service' => $service, 'postage' => (double)$postage);
				}
			}
		}
		if (sizeof($rates) == 0)
		{
			$quotes['error'] = 'No rates returned from production.shippingapis.com';
			return $quotes;
		}

		//Calculate Handling
		$quotes['handling'] = MODULE_SHIPPING_USPS_HANDLING;
		$quotes['rates'] = $rates;

		return $quotes;	
	}

	function check() {
		if (!isset($this->_check)) {
			$this->_check = check_module($this->module_key);
		}
		return $this->_check;
	}

	function install() {
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, configuration_values, date_added) values ('Enable USPS Shipping', 'MODULE_SHIPPING_USPS_STATUS', 'true', 'Do you want to offer USPS shipping?', '6', '0','true, false', now())");
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, configuration_values, date_added) values ('Enable USPS Address Info APIs Status', 'MODULE_SHIPPING_USPS_ADDR_INFO_STATUS', 'true', 'Do you want to use the Address Info APis?', '6', '0','true, false', now())");
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Enter the USPS User ID', 'MODULE_SHIPPING_USPS_USERID', 'NONE', 'Enter the USPS USERID assigned to you.', '6', '0', now())");
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Enter the USPS Password', 'MODULE_SHIPPING_USPS_PASSWORD', 'NONE', 'See USERID, above.', '6', '0', now())");
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Handling Fee', 'MODULE_SHIPPING_USPS_HANDLING', '0', 'Handling fee for this shipping method.', '6', '0', now())");
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, configuration_values, date_added) values ('Tax Class', 'MODULE_SHIPPING_USPS_TAX_CLASS', '0', 'Use the following tax class on the shipping fee.', '6', '0', 'tax_class_list()', now())");
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, configuration_values, date_added) values ('Shipping Zone', 'MODULE_SHIPPING_USPS_ZONE', '0', 'If a zone is selected, only enable this shipping method for that zone.', '6', '0', 'geo_zone_list()', now())");
		run_sql("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort Order', 'MODULE_SHIPPING_USPS_SORT_ORDER', '0', 'Sort order of display.', '6', '0', now())");
	}

	function remove() {
		remove_module($this->module_key);
	}
}
?>
